/********************************************************************** Socket example: Chat application, server component comm_s.c
*
* Compilation: gcc -o comm_s comm_s.c
*
* comm_s <port> is used to start a server on each end system,
* and comm_c <destination system> <port> is used to start an
* arbitrary number of clients.
* All messages written in the client are displayed at the respective
* destination server.
**********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <string.h>

/* Macro for easier output of IP addresses with printf() */
#define NIPQUAD(addr) \
               ((unsigned char *)&addr)[0], \
               ((unsigned char *)&addr)[1], \
               ((unsigned char *)&addr)[2], \
               ((unsigned char *)&addr)[3]

#define BUFSIZE 1024
char buf[BUFSIZE + 1];

/* Signal handler to accept the SIGCHLD signal when terminating
* child processes; otherwise, these zombie processes would remain.
*/
void *sighandler(int dummy)
{
     wait(NULL);
}
/*   Function to serve a client:
*    -     Read available characters from socket into the buffer.
*    -     Search for end-of-line character; if found, or if buffer full:
*          output message, move the rest forward, and repeat.
*    -     Abort, if error, or connection closed.
*/
void serve(int s, struct sockaddr_in *peer)
{
  
  ///////////////////////
  char recvType[5];
  recv(s, recvType, 4, 0);
  recvType[4] = 0;
  if (strncmp("FILE", recvType, 4) == 0)
  {
    
    printf("we got a file\n");
    return;
  }
  ///////////////////////

     int space, n;
     char *p, *q;
     q = p = buf; space = BUFSIZE;
     while (1) {
            if ((n = read(s, p, space)) <= 0) break;
            p += n; space -= n;
            while ((q < p) && (*q != '\n')) q++;
            while ((q < p) || !space) {
                   *q = 0;
                   printf("message from %d.%d.%d.%d %d: %s\n",
                   NIPQUAD(peer->sin_addr.s_addr), ntohs(peer->sin_port), buf);
                   if (q < p) q++;
                   memmove(buf, q, p - q);
                   n = q - buf; // Number of characters "done"
                   p -= n; space += n;
                   q = buf;
                   while ((q < p) && (*q != '\n')) q++;
            }
     }
     if (n < 0) perror("read");
     else if (p > buf) { // Output rest
             *p = 0;
             printf("message from %d.%d.%d.%d. %d: %s\n",
                  NIPQUAD(peer->sin_addr.s_addr), ntohs(peer->sin_port), buf);
     }
}

/* Main program:
* -   Process arguments
* -   Open socket and wait for connections
* -   Start separate process for each new connection
*/
int main(int argc, char *argv[])
{
    int s;
    struct sockaddr_in myaddr;
    int optval;
    if (argc != 2) {
          fprintf(stderr, "Usage: %s <port>\n", argv[0]); exit(1);
    }
    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
          perror("socket"); exit(1);
    }

    /*    Socket option SO_REUSEADDR: Allow bind(), even when old
          protocol instances are still using the address. */
    optval = 1;
    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))) {
             perror("setsockopt"); exit(1);
    }

    memset(&myaddr, 0, sizeof(myaddr));
    myaddr.sin_family = AF_INET;
    myaddr.sin_port = htons(atoi(argv[1]));
    myaddr.sin_addr.s_addr = INADDR_ANY;

    if (bind(s, (struct sockaddr *) &myaddr, sizeof(myaddr))) {
            perror("bind"); exit(1);
    }

    if (listen(s, SOMAXCONN)) {
             perror("listen"); exit(1);
    }

    /* Install signal handler for SIGCHLD signal */
    if (signal(SIGCHLD, (sig_t) sighandler) == SIG_ERR) {
            perror("signal"); exit(1);
    }

    while (1) {
           int new_s;
           struct sockaddr_in claddr;
           int claddrlen;

           claddrlen = sizeof(claddr);
           if ((new_s = accept(s, (struct sockaddr *) &claddr, &claddrlen)) < 0) {
                  perror("accept"); continue;
           }

           if (fork()) { /* Parent process */
                  close(new_s); /* New socket is used by child process only. */
           }
           else { /* Child process */
                 close(s); /* Old socket is used by parent process only. */
                 printf("connection from %d.%d.%d.%d %d\n",
                         NIPQUAD(claddr.sin_addr.s_addr), ntohs(claddr.sin_port));
                  serve(new_s, &claddr);
                  printf("connection from %d.%d.%d.%d %d closed\n",
                         NIPQUAD(claddr.sin_addr.s_addr), ntohs(claddr.sin_port));
                  exit(0);
                  }
    }
}

